package com.meilai.project.service.finance.supplier.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.meilai.project.dto.finance.supplier.SupplierDTO;
import com.meilai.project.dto.finance.supplier.SupplierListDTO;
import com.meilai.project.dto.finance.supplier.SupplierMaterialDTO;
import com.meilai.project.entity.finance.supplier.*;
import com.meilai.project.exception.CommonException;
import com.meilai.project.mapper.finance.supplier.*;
import com.meilai.project.service.finance.supplier.SupplierService;
import com.meilai.project.vo.finance.supplier.SupplierWebVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Slf4j
public class SupplierServiceImpl extends ServiceImpl<SupplierMapper, Supplier> implements SupplierService {

    @Autowired
    private SqlSessionTemplate sqlSessionTemplate;
    @Autowired
    private SupplierPicsMapper supplierPicsMapper;
    @Autowired
    private SupplierContactInfoMapper supplierContactInfoMapper;
    @Autowired
    private SupplierInvoiceInfoMapper supplierInvoiceInfoMapper;
    @Autowired
    private SupplierMaterialMapper supplierMaterialMapper;

    @Override
    public List<Supplier> getListByMaterialId(Long materialId) {
        List<Supplier> result = new ArrayList<>();
        List<SupplierMaterial> ms = supplierMaterialMapper.selectList(Wrappers.<SupplierMaterial>lambdaQuery()
                .eq(SupplierMaterial::getStatus, 1)
                .isNull(SupplierMaterial::getDeleted_at)
                .eq(SupplierMaterial::getMaterial_texture_id, materialId));
        if (CollectionUtils.isNotEmpty(ms)) {
            Set<Long> sIds = ms.stream().map(SupplierMaterial::getSupplier_id).collect(Collectors.toSet());
            if (CollectionUtils.isNotEmpty(sIds)) {
                result = list(Wrappers.<Supplier>lambdaQuery()
                        .eq(Supplier::getStatus, 1)
                        .isNull(Supplier::getDeleted_at)
                        .in(Supplier::getId, sIds));
            }
        }
        return result;
    }

    @Override
    public Page<SupplierWebVO> selectPageList(SupplierListDTO searchDTO) {
        Page<SupplierWebVO> page = searchDTO.createPage(SupplierWebVO.class);
        List<SupplierWebVO> listResult = baseMapper.selectPageList(page, searchDTO);
        page.setRecords(listResult);
        return page;
    }

    @Override
    public List<SupplierWebVO> selectList(SupplierListDTO searchDTO) {
        return baseMapper.selectPageList(null, searchDTO);
    }

    @Override
    public SupplierWebVO getOneById(Long id) {
        Supplier supplier = getById(id);
        List<SupplierPics> picList = supplierPicsMapper.selectList(new QueryWrapper<SupplierPics>().isNull("deleted_at").eq("supplier_id", id).eq("type", 1));
        List<SupplierContactInfo> contactList = supplierContactInfoMapper.selectList(new QueryWrapper<SupplierContactInfo>().isNull("deleted_at").eq("supplier_id", id));
        List<SupplierInvoiceInfo> invoiceList = supplierInvoiceInfoMapper.selectList(new QueryWrapper<SupplierInvoiceInfo>().isNull("deleted_at").eq("supplier_id", id));
        SupplierWebVO vo = new SupplierWebVO();
        BeanUtils.copyProperties(supplier, vo);
        vo.setBusiness_license_list(picList);
        vo.setContact_info_list(contactList);
        vo.setInvoice_info_list(invoiceList);
        return vo;
    }

    @Override
    public List<SupplierMaterial> getMaterialById(Long id) {
        return supplierMaterialMapper.selectList(new QueryWrapper<SupplierMaterial>().select("id", "supplier_id", "material_texture_id", "price")
                .isNull("deleted_at").eq("supplier_id", id));
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public boolean add(SupplierDTO dto) {
        List<Supplier> list = list(new QueryWrapper<Supplier>().isNull("deleted_at").eq("name", dto.getName()));
        if (list != null && list.size() > 0) throw new CommonException("该供应商名称已存在");
        Supplier supplier = new Supplier();
        BeanUtils.copyProperties(dto, supplier);
        boolean flag = save(supplier);
        batchInsert(supplier.getId(), dto.getBusiness_license_list(), dto.getContact_info_list(), dto.getInvoice_info_list(), false);
        return flag;
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public boolean edit(SupplierDTO dto) {
        Long supplier_id = dto.getId();
        List<Supplier> temp = list(new QueryWrapper<Supplier>().isNull("deleted_at").eq("name", dto.getName()).ne("id", supplier_id));
        if (temp != null && temp.size() > 0) throw new CommonException("该供应商名称已存在");
        List<SupplierPics> picList = dto.getBusiness_license_list(), insertPicList = new ArrayList<>(), updatePicList = new ArrayList<>();
        List<SupplierContactInfo> contactList = dto.getContact_info_list(), insertContactList = new ArrayList<>(), updateContactList = new ArrayList<>();
        List<SupplierInvoiceInfo> invoiceList = dto.getInvoice_info_list(), insertInvoiceList = new ArrayList<>(), updateInvoiceList = new ArrayList<>();
        // 获取之前添加的关系数据
        Map<Long, Long> picIdsMap = this.getIdsMap(supplierPicsMapper.getIdsBySupplierId(supplier_id));
        Map<Long, Long> contactIdsMap = this.getIdsMap(supplierContactInfoMapper.getIdsBySupplierId(supplier_id));
        Map<Long, Long> invoiceIdsMap = this.getIdsMap(supplierInvoiceInfoMapper.getIdsBySupplierId(supplier_id));
        for (int i = 0; i < picList.size(); i++) {
            SupplierPics o = picList.get(i);
            Long id = o.getId();
            if (id == null) insertPicList.add(o);
            else {
                updatePicList.add(o);
                if (!picIdsMap.isEmpty()) picIdsMap.remove(id);
            }
        }
        for (int i = 0; i < contactList.size(); i++) {
            SupplierContactInfo o = contactList.get(i);
            Long id = o.getId();
            if (id == null) insertContactList.add(o);
            else {
                updateContactList.add(o);
                if (!contactIdsMap.isEmpty()) contactIdsMap.remove(id);
            }
        }
        for (int i = 0; i < invoiceList.size(); i++) {
            SupplierInvoiceInfo o = invoiceList.get(i);
            Long id = o.getId();
            if (id == null) insertInvoiceList.add(o);
            else {
                updateInvoiceList.add(o);
                if (!invoiceIdsMap.isEmpty()) invoiceIdsMap.remove(id);
            }
        }
        Supplier supplier = new Supplier();
        BeanUtils.copyProperties(dto, supplier);
        boolean flag = updateById(supplier);
        batchInsert(supplier_id, insertPicList, insertContactList, insertInvoiceList, updatePicList, updateContactList, updateInvoiceList, false);
        // 剩余的ids赋值deleted_at为null
        if (!picIdsMap.isEmpty()) {
            List<Long> ids = picIdsMap.values().stream().collect(Collectors.toList()); //Map转List<Long>
            supplierPicsMapper.updateDeletedAtByIds(ids);
        }
        if (!contactIdsMap.isEmpty()) {
            List<Long> ids = contactIdsMap.values().stream().collect(Collectors.toList()); //Map转List<Long>
            supplierContactInfoMapper.updateDeletedAtByIds(ids);
        }
        if (!invoiceIdsMap.isEmpty()) {
            List<Long> ids = invoiceIdsMap.values().stream().collect(Collectors.toList()); //Map转List<Long>
            supplierInvoiceInfoMapper.updateDeletedAtByIds(ids);
        }
        return flag;
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public boolean delete(Long id) {
        Supplier temp = getById(id);
        if (temp == null) return false;
        Supplier supplier = new Supplier();
        supplier.setId(id);
        supplier.setDeleted_at(LocalDateTime.now());
        boolean flag = updateById(supplier);
        baseMapper.deleteSupplierRelationById(id);
        return flag;
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public boolean saveMaterial(SupplierMaterialDTO dto) {
        Long supplier_id = dto.getSupplier_id();
        List<SupplierMaterial> list = dto.getMaterial_list(), insertMaterialList = new ArrayList<>(), updateMaterialList = new ArrayList<>();
        List<Long> collect = list.stream().map(SupplierMaterial::getMaterial_texture_id).distinct().collect(Collectors.toList());
        if (list.size() != collect.size()) throw new CommonException("存在相同的材质，请重新选择");
        // 获取之前添加的物料
        Map<Long, Long> idsMap = this.getIdsMap(supplierMaterialMapper.getIdsBySupplierId(supplier_id));
        for (int i = 0; i < list.size(); i++) {
            SupplierMaterial material = list.get(i);
            Long id = material.getId();
            if (id == null) insertMaterialList.add(material);
            else {
                updateMaterialList.add(material);
                if (!idsMap.isEmpty()) idsMap.remove(id);
            }
        }
        batchInsert(insertMaterialList, updateMaterialList, false);
        // 剩余的ids赋值deleted_at为null
        if (!idsMap.isEmpty()) {
            List<Long> ids = idsMap.values().stream().collect(Collectors.toList()); //Map转List<Long>
//            supplierMaterialMapper.deleteBatchIds(ids); //物理删除
            supplierMaterialMapper.updateDeletedAtByIds(ids); //假删
        }
        return true;
    }

    private Map<Long, Long> getIdsMap(List<Long> list) {
        Map<Long, Long> idsMap = new HashMap<>();
        if (list != null && list.size() > 0)
            idsMap = list.stream().collect(Collectors.toMap(Function.identity(), o -> o)); //List<Long>转Map
        return idsMap;
    }

    private void batchInsert(Long supplier_id, List<SupplierPics> picList, List<SupplierContactInfo> contactList, List<SupplierInvoiceInfo> invoiceList, Boolean hasCatch) {
        batchInsert(supplier_id, picList, contactList, invoiceList, null, null, null, hasCatch);
    }

    private void batchInsert(Long supplier_id, List<SupplierPics> insertPicList, List<SupplierContactInfo> insertContactList, List<SupplierInvoiceInfo> insertInvoiceList,
                             List<SupplierPics> updatePicList, List<SupplierContactInfo> updateContactList, List<SupplierInvoiceInfo> updateInvoiceList,
                             Boolean hasCatch) {
        SqlSession session = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false);
        SupplierPicsMapper picMapper = session.getMapper(SupplierPicsMapper.class);
        SupplierContactInfoMapper contactMapper = session.getMapper(SupplierContactInfoMapper.class);
        SupplierInvoiceInfoMapper invoiceMapper = session.getMapper(SupplierInvoiceInfoMapper.class);
        try {
            //营业执照
            if (insertPicList != null && insertPicList.size() > 0) {
                insertPicList.forEach(o -> o.setSupplier_id(supplier_id));
                for (int i = 0; i < insertPicList.size(); i++) {
                    picMapper.insert(insertPicList.get(i));
                    if (i % 1000 == 999 || i == insertPicList.size() - 1) {
                        session.commit();
                        session.clearCache();
                    }
                }
            }
            //联系人信息
            if (insertContactList != null && insertContactList.size() > 0) {
                insertContactList.forEach(o -> o.setSupplier_id(supplier_id));
                for (int i = 0; i < insertContactList.size(); i++) {
                    contactMapper.insert(insertContactList.get(i));
                    if (i % 1000 == 999 || i == insertContactList.size() - 1) {
                        session.commit();
                        session.clearCache();
                    }
                }
            }
            //发票信息
            if (insertInvoiceList != null && insertInvoiceList.size() > 0) {
                insertInvoiceList.forEach(o -> o.setSupplier_id(supplier_id));
                for (int i = 0; i < insertInvoiceList.size(); i++) {
                    invoiceMapper.insert(insertInvoiceList.get(i));
                    if (i % 1000 == 999 || i == insertInvoiceList.size() - 1) {
                        session.commit();
                        session.clearCache();
                    }
                }
            }

            //更新供应商关系表
            if (updatePicList != null && updatePicList.size() > 0) {
                for (int i = 0; i < updatePicList.size(); i++) {
                    picMapper.updateById(updatePicList.get(i));
                    if (i % 1000 == 999 || i == updatePicList.size() - 1) {
                        session.commit();
                        session.clearCache();
                    }
                }
            }
            if (updateContactList != null && updateContactList.size() > 0) {
                for (int i = 0; i < updateContactList.size(); i++) {
                    contactMapper.updateById(updateContactList.get(i));
                    if (i % 1000 == 999 || i == updateContactList.size() - 1) {
                        session.commit();
                        session.clearCache();
                    }
                }
            }
            if (updateInvoiceList != null && updateInvoiceList.size() > 0) {
                for (int i = 0; i < updateInvoiceList.size(); i++) {
                    invoiceMapper.updateById(updateInvoiceList.get(i));
                    if (i % 1000 == 999 || i == updateInvoiceList.size() - 1) {
                        session.commit();
                        session.clearCache();
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            if (hasCatch) session.rollback();
            else throw new CommonException("批量插入失败：" + e.getMessage());
        } finally {
            session.close();
        }
    }

    private void batchInsert(List<SupplierMaterial> insertMaterialList, List<SupplierMaterial> updateMaterialList, Boolean hasCatch) {
        SqlSession session = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false);
        SupplierMaterialMapper materialMapper = session.getMapper(SupplierMaterialMapper.class);
        try {
            //插入物料
            if (insertMaterialList != null && insertMaterialList.size() > 0) {
                for (int i = 0; i < insertMaterialList.size(); i++) {
                    materialMapper.insert(insertMaterialList.get(i));
                    if (i % 1000 == 999 || i == insertMaterialList.size() - 1) {
                        session.commit();
                        session.clearCache();
                    }
                }
            }
            //更新物料
            if (updateMaterialList != null && updateMaterialList.size() > 0) {
                for (int i = 0; i < updateMaterialList.size(); i++) {
                    materialMapper.updateById(updateMaterialList.get(i));
                    if (i % 1000 == 999 || i == updateMaterialList.size() - 1) {
                        session.commit();
                        session.clearCache();
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            if (hasCatch) session.rollback();
            else throw new CommonException("批量插入失败：" + e.getMessage());
        } finally {
            session.close();
        }
    }
}
